﻿#ifndef _CELLLOG_HPP_
#define _CELLLOG_HPP_

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "CELLTask.hpp"
#include "CELLTimestamp.hpp"

class CELLLog
{
#ifdef _DEBUG
#ifndef CELLLog_Debug
#define CELLLog_Debug(...) CELLLog::Debug(__VA_ARGS__)
#endif // #ifndef CELLLog_Debug
#else
#ifndef CELLLog_Debug
#define CELLLog_Debug(...)
#endif // #ifndef CELLLog_Debug
#endif // #ifdef _DEBUG

#define CELLLog_Info(...) CELLLog::Info(__VA_ARGS__)
#define CELLLog_Warning(...) CELLLog::Warning(__VA_ARGS__)
#define CELLLog_Error(...) CELLLog::Error(__VA_ARGS__)
#define CELLLog_pError(...) CELLLog::pError(__VA_ARGS__)
public:
	~CELLLog()
	{
		_taskServer.Close();
		if (_logFile)
		{
			fclose(_logFile);
			_logFile = nullptr;
		}
	}

	// 单例
	static CELLLog& Instance()
	{
		static CELLLog sLog;
		return sLog;
	}

	static void pError(const char* pStr)
	{
		pError("%s", pStr);
	}

	template<typename... Args>
	static void pError(const char* pFormat, Args... args)
	{
#ifdef _WIN32
		auto errCode = GetLastError();

		CELLLog* pLog = &Instance();
		pLog->_taskServer.AddTask([=]() {
			char text[256] = { 0 };
			FormatMessageA(
				FORMAT_MESSAGE_FROM_SYSTEM,
				NULL, errCode,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPSTR)&text, 256, NULL);
			EchoReal(true, "pError: ", pFormat, args...);
			EchoReal(false, "pError: ", "errno<%d>, errmsg:%s", errCode, text);
		});
#else
		auto errCode = errno;
		CELLLog* pLog = &Instance();
		pLog->_taskServer.AddTask([=]() {
			EchoReal(true, "pError: ", pFormat, args...);
			EchoReal(true, "pError: ", "errno<%d>, errmsg<%s>", errCode, strerror(errCode));
		});
#endif
	}

	// Error
	static void Error(const char* pStr)
	{
		Error("%s", pStr);
	}

	template<typename... Args>
	static void Error(const char* pFormat, Args... args)
	{
		Echo("Error: ", pFormat, args...);
	}

	// Warning
	static void Warning(const char* pStr)
	{
		Warning("%s", pStr);
	}

	template<typename... Args>
	static void Warning(const char* pFormat, Args... args)
	{
		Echo("Warning: ", pFormat, args...);
	}

	// Info
	static void Info(const char* pStr)
	{
		Info("%s", pStr);
	}

	template<typename... Args>
	static void Info(const char* pFormat, Args... args)
	{
		Echo("Info: ", pFormat, args...);
	}

	// Debug
	static void Debug(const char* pStr)
	{
		Debug("%s", pStr);
	}

	template<typename... Args>
	static void Debug(const char* pFormat, Args... args)
	{
		Echo("Debug: ", pFormat, args...);
	}

	template<typename... Args>
	static void Echo(const char* type, const char* pFormat, Args... args)
	{
		CELLLog* pLog = &Instance();
		pLog->_taskServer.AddTask([type, pLog, pFormat, args...]() {
			EchoReal(true, type, pFormat, args...);
		});
	}

	template<typename... Args>
	static void EchoReal(bool br, const char* type, const char* pFormat, Args... args)
	{
		CELLLog* pLog = &Instance();
		if (pLog->_logFile)
		{
			auto t = system_clock::now();
			auto tNow = system_clock::to_time_t(t);
			std::tm* now = localtime(&tNow);
			fprintf(pLog->_logFile, "[%d-%d-%d %d:%d:%d]",
				now->tm_year + 1900, now->tm_mon + 1,
				now->tm_mday, now->tm_hour,
				now->tm_min, now->tm_sec);
			if (type)
				fprintf(pLog->_logFile, "%s", type);
			fprintf(pLog->_logFile, pFormat, args...);
			if (br)
				fprintf(pLog->_logFile, "\n");
			fflush(pLog->_logFile);
		}
		printf(pFormat, args...);
		if (br)
			printf("\n");
	}

	// 设置日志路径
	void setLogPath(const char* logName, const char* mode)
	{
		if (_logFile)
		{
			Info("CELLLog::setLogPath close a exists fd!");
			// 打开过这个文件
			fclose(_logFile);
		}
		static char logPath[256] = { 0 };
		auto t = system_clock::now();
		auto tNow = system_clock::to_time_t(t);
		// std::tm* now = gmtime(&tNow);
		std::tm* now = localtime(&tNow);
		sprintf(logPath, "%s[%d_%d_%d__%d_%d_%d].txt", logName, 
			now->tm_year + 1900, now->tm_mon + 1,
			now->tm_mday, now->tm_hour,
			now->tm_min, now->tm_sec);
		_logFile = fopen(logPath, mode);
		if (_logFile)
		{
			Info("CELLLog::setLogPath success, <%s, %s>", logPath, mode);
		}
		else
		{
			Error("CELLLog::setLogPath failed, <%s, %s>\n", logPath, mode);
		}
	}
private:
	CELLLog()
	{
		// 构造开启日志记录
		_taskServer.Start();
	}

	FILE* _logFile = nullptr;

	CellTaskServer _taskServer;
};

#endif // #ifndef _CELLLOG_HPP_
